home *** CD-ROM | disk | FTP | other *** search
/ Usenet 1993 July / InfoMagic USENET CD-ROM July 1993.ISO / sources / misc / volume2 / pstrings / part01 next >
Encoding:
Internet Message Format  |  1991-08-07  |  33.3 KB

  1. From: ian@unix.computer-science.manchester.ac.uk (Ian Cottam)
  2. Newsgroups: comp.sources.misc
  3. Subject: v02i075: Unbounded Strings Package in ISO level 1 Pascal
  4. Message-ID: <7511@ncoast.UUCP>
  5. Date: 15 Mar 88 10:37:01 GMT
  6. Approved: allbery@ncoast.UUCP
  7.  
  8. comp.sources.misc: Volume 2, Issue 75
  9. Submitted-By: "Ian Cottam" <ian@unix.computer-science.manchester.ac.uk>
  10. Archive-Name: pstrings/part01
  11.  
  12. #! /bin/sh
  13. # This is a shell archive, meaning:
  14. # 1. Remove everything above the #! /bin/sh line.
  15. # 2. Save the resulting text in a file.
  16. # 3. Execute the file with /bin/sh (not csh) to create the files:
  17. #    README
  18. #    strings.h
  19. #    CtoS.p
  20. #    assignS.p
  21. #    compare.p
  22. #    concatS.p
  23. #    disposeS.p
  24. #    emptyS.p
  25. #    eqS.p
  26. #    finalS.p
  27. #    first.p
  28. #    geS.p
  29. #    getsubS.p
  30. #    gtS.p
  31. #    indexS.p
  32. #    initS.p
  33. #    initvalparamS.p
  34. #    leS.p
  35. #    lengthS.p
  36. #    ltS.p
  37. #    matchS.p
  38. #    mk.p
  39. #    mkS.p
  40. #    mkStaticS.p
  41. #    neS.p
  42. #    newS.p
  43. #    next.p
  44. #    readS.p
  45. #    readtS.p
  46. #    repS.p
  47. #    updateS.p
  48. #    writeS.p
  49. #    writelnS.p
  50. #    Makefile
  51. # This archive created: Tue Mar 15 10:11:49 1988
  52. export PATH; PATH=/bin:$PATH
  53. if test -f 'README'
  54. then
  55.     echo shar: will not over-write existing file "'README'"
  56. else
  57. cat << \SHAR_EOF > 'README'
  58.  
  59. This is an Unbounded-length Strings package I wrote for our
  60. first year undergrads to use some years ago.  It is written in
  61. and assumes you are using an ISO level 1 conforming Pascal
  62. compiler. (If they come pretty close e.g. SUN Pascal then you
  63. will be alright.  N.B. Berkeley pc is NOT close enough -- at least
  64. the version I have which is that with 4.3BSD.)
  65.  
  66. I have used the package with: SUN Pascal, VAX-VMS-Pascal, and York Pascal
  67. (a UN*X/portable Pascal compiler) on VAX-UN*X.
  68.  
  69. See the strings.h header file for some implementation comments.
  70.  
  71. Where you put things like #include is, of course, compiler specific.
  72. The distributed version should work on SUNs; other systems will require
  73. you to make trivial (hopefully) mods.  Even on SUNs you may have trouble
  74. with erroneous complaints from /usr/lib/pc3 -- the separate compilation
  75. checker -- about redefinitions.  Personally, I don't bother with
  76. /usr/lib/pc3.
  77.  
  78. Good luck
  79. -Ian Cottam
  80. Univ of Manchester, Dept of Comp Sci, Oxford Rd, Manchester
  81. M13 9PL, UK, ian@ux.cs.man.ac.uk
  82.  
  83. SHAR_EOF
  84. fi # end of overwriting check
  85. if test -f 'strings.h'
  86. then
  87.     echo shar: will not over-write existing file "'strings.h'"
  88. else
  89. cat << \SHAR_EOF > 'strings.h'
  90. {
  91. *
  92. * String handling package in Pascal (ISO Level 1).
  93. *
  94. *   This package of procedures and functions implements unbounded
  95. * Strings of Characters. 
  96. *
  97. * N.B. All string variables MUST be initialised via initS(s).
  98. *      Assignment MUST be via assignS(dest, src).
  99. *      If desired, storage may be reclaimed via finalS(s).
  100. *  i.e.
  101. *         var s,t: String;
  102. *             . . .
  103. *       initS(s); initS(t);
  104. *          . . .
  105. *       assignS(t, concatS(mkS('Join this string '), mkS('to this')));
  106. *       assignS(s, t);
  107. *          . . .
  108. *       finalS(s); finalS(t);
  109. *
  110. * Additionally, string by-value parameters must be initialised by calling
  111. * initvalparamS(s).
  112. * * e.g.
  113. *
  114. *    procedure p(s:String);
  115. *     begin writelnS(output, concatS(s, concatS(s,s)))
  116. *     end;
  117. *
  118. * MUST be written as:
  119. *
  120. *    procedure p(s:String);
  121. *     begin initvalparamS(s);
  122. *           writelnS(output, concatS(s, concatS(s,s)))
  123. *     end;
  124. * (This is because the package performs incremental garbage collection
  125. *  on unassigned strings, but extant by-value references cannot be
  126. *  detected.)
  127. *
  128. *
  129. *
  130. * Implementation Issues:
  131. *
  132. * The representation is a header record containing a
  133. * length field, a reference count, and a packed array [1..slength]
  134. * of Char, followed by zero or more `tail' chunks - also
  135. * containing a packed array [1..slength] of Char.
  136. * The empty string is represented by nil.  Beware of
  137. * s1 := s2   this copies pointers (!) not the strings themselves.
  138. * `:=' between strings should not be used; it cannot be banned
  139. * because types inherit assignment in Pascal.
  140. * The procedure     assignS(dest, source) 
  141. * should be used to copy strings, it uses the reference count to
  142. * avoid copying.  Only if updateS is used will the string
  143. * actually be copied (if the ref count is > 1).
  144. *
  145. *   All the routines end with a capital S.
  146. *
  147. * Ian Cottam, University of Manchester,  NOV.85. revised MAR.86 and DEC.86.
  148. *                                        revised MAR.88 - better names,
  149. *                     plus use of initvalparamS.
  150. }
  151.  
  152. { -- string chunk length - any length > 0 will work }
  153. const slength = 16;
  154.  
  155. type
  156.  
  157.   String = ^ stringrec;
  158.  
  159.  
  160.   Nat0 = 0 .. maxint;
  161.  
  162.   Nat1 = 1 .. maxint;
  163.    
  164.  
  165.   stringtail = ^ tailrec;
  166.  
  167.   stringrec = record
  168.     LEN:  Nat1; { -- Note: no 0 as nil represents '' }
  169.     REFS: Nat0; { -- How many refs are there to this string }
  170.                 { -- N.B. only = 0 when string generated by a function }
  171.     HEAD: packed array [1..slength] of Char;
  172.     TAIL: stringtail
  173.       end;
  174.  
  175.   tailrec   = record
  176.         MORE: packed array [1..slength] of Char;
  177.         REST: stringtail
  178.           end;
  179.  
  180.  
  181.  { -- Result of compare - internal function to ADT }
  182.  StrCmpResult = (lt, eq, gt);
  183.  
  184.  { -- type for sequencing thru strings - internal to ADT at the moment}
  185.  CharOfString = record 
  186.                    POS: 1..slength;
  187.                   case KIND: Boolean of
  188.              true:  (HD: String);
  189.              false: (TL: stringtail)
  190.                 end;
  191.  
  192.  
  193. {************ function and procedure headings **************}
  194.  
  195. { --   ...   in Alphabetical order   ...           }
  196.  
  197.  
  198.  
  199. procedure assignS(var lhs: String; rhs: String);
  200. {
  201. * lhs := rhs 
  202. }
  203. external;
  204.  
  205.  
  206.  
  207. { ***** AUXILIARY FUNCTION ***** }
  208. function compare(left, right:String):StrCmpResult; 
  209. {
  210. * String comparison - used in the impl. of eqS, neS, ltS, etc.
  211. }
  212. external;
  213.  
  214.  
  215. function concatS(s1, s2: String):String;
  216. {
  217. * Returns s1 + s2
  218. * Concatenates s1 and s2.
  219. }
  220. external;
  221.  
  222.  
  223.  
  224. function CtoS(c: Char):String;
  225. {
  226. * Converts a character into a string of length 1
  227. }
  228. external;
  229.  
  230.  
  231.  
  232. procedure disposeS(var s: String);
  233. {
  234. * reclaims the storage associated with the string s
  235. }
  236. external;
  237.  
  238.  
  239.  
  240. function emptyS: String;
  241. {
  242. * Returns the empty or null string ''
  243. }
  244. external;
  245.  
  246.  
  247.  
  248. function eqS(left,right: String):Boolean;
  249. {
  250. * left = right
  251. }
  252. external;
  253.  
  254.  
  255. procedure finalS(var s: String);
  256. {
  257. * same as disposeS but possibly better name
  258. * reclaims the storage associated with the string s
  259. }
  260. external;
  261.  
  262.  
  263.  
  264. { ***** AUXILIARY FUNCTION ***** }
  265. procedure first(var c:CharOfString; var s: String);
  266. {
  267. * c initialised to point to the first char of s
  268. *
  269. * precondition
  270. *     s <> ''
  271. }
  272. external;
  273.  
  274.  
  275.  
  276. function geS(left,right: String):Boolean;
  277. {
  278. * left >= right
  279. }
  280. external;
  281.  
  282.  
  283.  
  284. function getsubS(s: String; frompos, topos: Nat0):String;
  285. {
  286. * Returns s[frompos..topos]
  287. * Extracts a substring of s.
  288. *  returns ''  if frompos..topos not in range.
  289. }
  290. external;
  291.  
  292.  
  293.  
  294. function gtS(left,right: String):Boolean;
  295. {
  296. * left > right
  297. }
  298. external;
  299.  
  300.  
  301.  
  302. function indexS(s: String; i: Nat1):Char;
  303. {
  304. * Returns s[i]
  305. *
  306. * precondition:
  307. *     i <= lengthS(s)
  308. }
  309. external;
  310.  
  311.  
  312.  
  313. procedure initS(var s: String);
  314. {
  315. * Initialises s to be the empty or null string ''
  316. * Same as newS, but possibly less confusing name.
  317. }
  318. external;
  319.  
  320.  
  321.  
  322. procedure initvalparamS(var s: String);
  323. {
  324. * Initialises s, which should be a value parameter, to be
  325. * safely useable within the current procedure.
  326. }
  327. external;
  328.  
  329.  
  330.  
  331. function leS(left,right: String):Boolean;
  332. {
  333. * left <= right
  334. }
  335. external;
  336.  
  337.  
  338.  
  339. function lengthS(s: String):Nat0;
  340. {
  341. * Returns the dynamic length of a string
  342. }
  343. external;
  344.  
  345.  
  346.  
  347. function ltS(left,right: String):Boolean;
  348. {
  349. * left < right
  350. }
  351. external;
  352.  
  353.  
  354.  
  355. function matchS(s, pat: String):Nat0;
  356. {
  357. * Returns position of pat in s or 0 if not present.
  358. * Empty strings are not considered present!
  359. }
  360. external;
  361.  
  362.  
  363.  
  364. { ***** AUXILIARY FUNCTION ***** }
  365. function mk(var static: packed array [lo..hi:Integer] of Char;
  366.             limit: Integer):String;
  367. {
  368. * Converts a static Pascal string into a (dynamic) String.
  369. * From lo to limit rather than hi.
  370. * This internal procedure may be made generally available
  371. * should there be a demand.
  372. }
  373. external;
  374.  
  375.  
  376. function mkS(static: packed array [lo..hi:Integer] of Char):String;
  377. {
  378. * Converts a static Pascal string into a (dynamic) String.
  379. }
  380. external;
  381.  
  382.  
  383.  
  384. procedure mkStaticS(s: String; var p: packed array[lo..hi:Integer] of Char);
  385. {
  386. * Converts a dynamic string into a static string.
  387. * p is null padded if necessary.
  388. * Info will be lost if lengthS(s) > hi-lo+1.
  389. }
  390. external;
  391.  
  392.  
  393.  
  394. function neS(left,right: String):Boolean;
  395. {
  396. * left <> right
  397. }
  398. external;
  399.  
  400.  
  401.  
  402. procedure newS(var s: String);
  403. {
  404. * Initialises s to be the empty or null string ''
  405. }
  406. external;
  407.  
  408.  
  409.  
  410. { ***** AUXILIARY FUNCTION ***** }
  411. procedure next(var c: CharOfString; var ch: Char);
  412. {
  413. * c is advanced to point to next char in its string and current char
  414. * returned in ch
  415. *
  416. * precondition
  417. *     c initialised by call to first and not at end of string
  418. }
  419. external;
  420.  
  421.  
  422.  
  423. procedure readS(var f: Text; var s: String);
  424. {
  425. * Reads a string from text file f; eoln terminating.  The input is
  426. * left pointing to the beginning of the next line, if any.
  427. *
  428. * precondition:
  429. *    f open for reading & not eof(f)
  430. }
  431. external;
  432.  
  433.  
  434.  
  435.  
  436. procedure readtS(var f: Text; var s: String; function stop(c:Char):Boolean);
  437. {
  438. * Reads a string from text file f; eoln or stop(c) returning true
  439. * (whichever occurs first) terminating.  In either case,
  440. * input is left positioned at the terminator.
  441. *
  442. * precondition:
  443. *    f open for reading & not eof(f)
  444. }
  445. external;
  446.  
  447.  
  448.  
  449. function repS(s: String; n: Nat0):String;
  450. {
  451. * Returns s * n
  452. * Replicates s, n times.
  453. }
  454. external;
  455.  
  456.  
  457.  
  458. procedure updateS(var s: String; i: Nat1; c:Char);
  459. {
  460. * Updates the string s at position  i  with the char c.
  461. * if i > lengthS(s), s is first space filled upto i-1.
  462. }
  463. external;
  464.  
  465.  
  466.  
  467. procedure writeS(var f: Text; s: String);
  468. {
  469. * Write the dynamic string s to file f
  470. *
  471. * precondition:
  472. *    f open for writing    
  473. }
  474. external;
  475.  
  476.  
  477.  
  478. procedure writelnS(var f: Text; s: String);
  479. {
  480. * Write the dynamic string s to file f followed by an eoln marker
  481. *
  482. * precondition:
  483. *    f open for writing    
  484. }
  485. external;
  486. SHAR_EOF
  487. fi # end of overwriting check
  488. if test -f 'CtoS.p'
  489. then
  490.     echo shar: will not over-write existing file "'CtoS.p'"
  491. else
  492. cat << \SHAR_EOF > 'CtoS.p'
  493.  
  494.  
  495.  
  496.  
  497. # include "strings.h"
  498.  
  499. function CtoS{(c: Char):String};
  500. {
  501. * Converts a character into a string of length 1
  502. }
  503.    var ss: packed array [1 .. 1] of Char;
  504. begin
  505.     ss[1] := c;
  506.     CtoS  := mkS(ss)
  507. end{ -- CtoS};
  508. SHAR_EOF
  509. fi # end of overwriting check
  510. if test -f 'assignS.p'
  511. then
  512.     echo shar: will not over-write existing file "'assignS.p'"
  513. else
  514. cat << \SHAR_EOF > 'assignS.p'
  515.  
  516.  
  517.  
  518.  
  519. # include "strings.h"
  520.  
  521. procedure assignS{(var lhs: String; rhs: String)};
  522. {
  523. * lhs := rhs
  524. }
  525. begin
  526.      if lhs <> rhs then begin { -- Care with case, e.g., assignS(x,x) }
  527.          disposeS(lhs);
  528.          if rhs = nil then { -- Empty string } lhs := nil
  529.          else begin
  530.         lhs := rhs;    { -- Ref. copy }
  531.         with rhs^ do REFS := REFS+1
  532.          end
  533.      end
  534. end{ -- assignS};
  535. SHAR_EOF
  536. fi # end of overwriting check
  537. if test -f 'compare.p'
  538. then
  539.     echo shar: will not over-write existing file "'compare.p'"
  540. else
  541. cat << \SHAR_EOF > 'compare.p'
  542.  
  543.  
  544.  
  545.  
  546. # include "strings.h"
  547.  
  548. function compare{(left, right: String):StrCmpResult};
  549.    var lenl, lenr: Nat0;  ltail, rtail: stringtail;
  550.        state: (GoOn, Less, Greater, Stop);
  551. begin
  552.   lenl  := lengthS(left); lenr  := lengthS(right);
  553.   { -- Do trivial cases first }
  554.   if lenl = 0 then
  555.     if lenr = 0 then compare := eq else compare := lt
  556.   else    if lenr = 0 then compare := gt else begin
  557.    { -- Non-trivial cases - both left and right are non empty }
  558.    ltail := left^.TAIL;    rtail := right^.TAIL;
  559.    if left^.HEAD < right^.HEAD then state := Less else
  560.    if left^.HEAD > right^.HEAD then state := Greater else
  561.    if (ltail = nil) or (rtail = nil)
  562.    then state := Stop
  563.    else state := GoOn;
  564.    { -- Check tails if necessary }
  565.    while state = GoOn do
  566.     if ltail^.MORE < rtail^.MORE then state := Less else
  567.     if ltail^.MORE > rtail^.MORE then state := Greater else
  568.     if (ltail^.REST = nil) or (rtail^.REST = nil)
  569.     then state := Stop
  570.     else
  571.      begin ltail := ltail^.REST; rtail := rtail^.REST end;
  572.    { -- Final check for differing lengths (etc.) }
  573.    case state of
  574.     Less:     compare := lt;
  575.     Greater: compare := gt;
  576.     Stop:     if lenl < lenr then compare := lt else
  577.          if lenl > lenr then compare := gt
  578.          else compare := eq
  579.    end
  580.   end;
  581.   { -- comparison may have involved constant strings }
  582.   if left  <> nil then if  left^.REFS = 0 then disposeS(left);
  583.   if right <> nil then if right^.REFS = 0 then disposeS(right)
  584. end{ -- compare};
  585. SHAR_EOF
  586. fi # end of overwriting check
  587. if test -f 'concatS.p'
  588. then
  589.     echo shar: will not over-write existing file "'concatS.p'"
  590. else
  591. cat << \SHAR_EOF > 'concatS.p'
  592.  
  593.  
  594.  
  595.  
  596. # include "strings.h"
  597.  
  598. function concatS{(s1, s2: String):String};
  599. {
  600. * Returns s1 + s2
  601. * Concatenates s1 and s2.
  602. }
  603.    var t: String;  { -- Result is built in t }
  604.        l, r, End1: stringtail;
  605.        StillInHeadOfT, InTailOfT, InTailOfS2: Boolean;
  606.        i, j: Nat1;
  607.        tindx, rindx: 1..slength;
  608.        null: Char;
  609. begin
  610.  t := nil;
  611.  null := chr(0);
  612.  { -- Deal with trivial cases first }
  613.  if s1 = nil then concatS := s2 else
  614.  if s2 = nil then concatS := s1 else
  615.  { -- Both s1 and s2 are non-empty }
  616.   begin
  617.     new(t);
  618.     with t^ do begin
  619.       LEN := s1^.LEN + s2^.LEN;
  620.       { -- Copy head of s1 }
  621.       HEAD := s1^.HEAD;
  622.       TAIL := nil;
  623.           { -- Allocate and link in any extra string chunks needed }
  624.         for i := 1 to (LEN-1) div slength do begin
  625.             new(l);
  626.         { -- pad with nulls if chunk is last one }
  627.         if i=1 then
  628.          for j:=1 to slength do l^.MORE[j] := null;
  629.             l^.REST := TAIL;
  630.             TAIL := l
  631.       end;
  632.           { -- Loop through copying string tail of s1, if required }
  633.       l := TAIL;  End1 := TAIL; r := s1^.TAIL;
  634.       for i := 1 to (s1^.LEN-1) div slength  do begin
  635.            l^.MORE := r^.MORE;
  636.         End1 := l; 
  637.            l := l^.REST;
  638.            r := r^.REST
  639.          end;
  640.       { -- End1 points to the last tail entry (partially) filled}
  641.       if s1^.LEN mod slength <> 0 then l := End1;
  642.       r := s2^.TAIL;
  643.       { -- Loop thru copying s2 to end of t char by char! }
  644.       tindx := s1^.LEN mod slength + 1;
  645.       rindx := 1; 
  646.       StillInHeadOfT := s1^.LEN < slength;
  647.       InTailOfT := false;  InTailOfS2 := false;
  648.       for i := 1 to s2^.LEN do begin
  649.         if  StillInHeadOfT then begin
  650.              HEAD[tindx] := s2^.HEAD[rindx];
  651.              StillInHeadOfT := tindx < slength
  652.         end
  653.         else
  654.         if i <= slength then begin
  655.             InTailOfT := true;
  656.             l^.MORE[tindx] := s2^.HEAD[rindx]
  657.         end
  658.         else begin
  659.             InTailOfS2 := true;
  660.             l^.MORE[tindx] := r^.MORE[rindx]
  661.         end;
  662.         { -- Always inc indices and step down lists if req. }
  663.         tindx := tindx mod slength + 1;
  664.         if (tindx = 1) and InTailOfT  then l := l^.REST;
  665.         rindx := rindx mod slength + 1;
  666.         if (rindx = 1) and InTailOfS2 then r := r^.REST
  667.       end
  668.       end{ -- with};
  669.     { -- Make 0 ref count }
  670.     t^.REFS := 0;
  671.     { -- Tidy up any intermediate storage }
  672.     if s1 <> nil then if s1^.REFS = 0 then disposeS(s1);
  673.     if s2 <> nil then if s2^.REFS = 0 then disposeS(s2);
  674.     concatS := t
  675.  end
  676. end{ -- concatS};
  677. SHAR_EOF
  678. fi # end of overwriting check
  679. if test -f 'disposeS.p'
  680. then
  681.     echo shar: will not over-write existing file "'disposeS.p'"
  682. else
  683. cat << \SHAR_EOF > 'disposeS.p'
  684.  
  685.  
  686.  
  687.  
  688. # include "strings.h"
  689.  
  690. procedure disposeS{(var s: String)};
  691. {
  692. * reclaims the storage associated with the string s
  693. }
  694.    var t, next: stringtail;
  695. begin
  696.   if s = nil then { -- Do nothing } else
  697.      if s^.REFS < 2 then begin { -- Only ref. to this string }
  698.     t := s^.TAIL;
  699.     dispose(s); s := nil; { -- emptyS }
  700.     while t <> nil do begin
  701.         next := t^.REST;
  702.         dispose(t);
  703.         t := next
  704.     end
  705.      end
  706.      else begin
  707.     { -- Decrement the references count, and make s = the empty string }
  708.     with s^ do REFS := REFS-1;
  709.     s := nil
  710.      end
  711. end{ -- disposeS};
  712. SHAR_EOF
  713. fi # end of overwriting check
  714. if test -f 'emptyS.p'
  715. then
  716.     echo shar: will not over-write existing file "'emptyS.p'"
  717. else
  718. cat << \SHAR_EOF > 'emptyS.p'
  719.  
  720.  
  721.  
  722.  
  723. # include "strings.h"
  724.  
  725. function emptyS{: String};
  726. {
  727. * Returns the empty or null string ''
  728. }
  729. begin
  730.     emptyS := nil
  731. end{ -- emptyS};
  732. SHAR_EOF
  733. fi # end of overwriting check
  734. if test -f 'eqS.p'
  735. then
  736.     echo shar: will not over-write existing file "'eqS.p'"
  737. else
  738. cat << \SHAR_EOF > 'eqS.p'
  739.  
  740.  
  741.  
  742.  
  743. # include "strings.h"
  744.  
  745. function eqS{(left,right: String):Boolean};
  746. {
  747. * left = right
  748. }
  749. begin
  750.     eqS := compare(left, right) = eq
  751. end{ -- eqS};
  752. SHAR_EOF
  753. fi # end of overwriting check
  754. if test -f 'finalS.p'
  755. then
  756.     echo shar: will not over-write existing file "'finalS.p'"
  757. else
  758. cat << \SHAR_EOF > 'finalS.p'
  759.  
  760.  
  761.  
  762.  
  763. # include "strings.h"
  764.  
  765. procedure finalS{(var s: String)};
  766. {
  767. * reclaims the storage associated with the string s
  768. }
  769. begin
  770.     disposeS(s)
  771. end{ -- finalS};
  772. SHAR_EOF
  773. fi # end of overwriting check
  774. if test -f 'first.p'
  775. then
  776.     echo shar: will not over-write existing file "'first.p'"
  777. else
  778. cat << \SHAR_EOF > 'first.p'
  779.  
  780.  
  781.  
  782.  
  783. # include "strings.h"
  784.  
  785. procedure first{(var c:CharOfString; var s: String)};
  786. {
  787. * c initialised to point to the first char of s
  788. *
  789. * precondition
  790. *     s <> ''
  791. }
  792. begin
  793.     with c do begin
  794.         KIND := true; { -- head record }
  795.           HD := s;
  796.          POS := 1
  797.     end
  798. end{ -- first};
  799. SHAR_EOF
  800. fi # end of overwriting check
  801. if test -f 'geS.p'
  802. then
  803.     echo shar: will not over-write existing file "'geS.p'"
  804. else
  805. cat << \SHAR_EOF > 'geS.p'
  806.  
  807.  
  808.  
  809.  
  810. # include "strings.h"
  811.  
  812. function geS{(left,right: String):Boolean};
  813. {
  814. * left >= right
  815. }
  816. begin
  817.     geS := compare(left, right) <> lt
  818. end{ -- geS};
  819. SHAR_EOF
  820. fi # end of overwriting check
  821. if test -f 'getsubS.p'
  822. then
  823.     echo shar: will not over-write existing file "'getsubS.p'"
  824. else
  825. cat << \SHAR_EOF > 'getsubS.p'
  826.  
  827.  
  828.  
  829.  
  830. # include "strings.h"
  831.  
  832.  
  833. function getsubS{(s: String; frompos, topos: Nat0):String};
  834. {
  835. * Returns s[frompos..topos]
  836. * Extracts a substring of s.
  837. *  returns ''  if frompos..topos not in range.
  838. }
  839.    const BufferLength = 512;
  840.    var t: String; j,i, stoppos: Nat1; ch: Char; sp: CharOfString;
  841.        buf: packed array [1..BufferLength] of Char;
  842. begin
  843.     t := nil; { -- empty string }
  844.     if topos <= lengthS(s) then begin
  845.        { --  convert max(BufferLength) chars to fixed string }
  846.        if topos-frompos+1 > BufferLength then
  847.         stoppos := frompos+BufferLength-1
  848.        else
  849.         stoppos := topos;
  850.        j := 1;
  851.        first(sp, s);
  852.        for i := 1 to frompos-1 do next(sp, ch);
  853.        for i := frompos to stoppos do begin
  854.         next(sp, ch);
  855.         buf[j] := ch;
  856.         j := j+1
  857.        end{ -- for};
  858.        { --  convert to String }
  859.        if j <> 1 then { --  positive slice }
  860.            t := mk(buf, j-1);
  861.        { --  check any more left }
  862.        if topos <> stoppos then
  863.         t := concatS(t,  getsubS(s, stoppos+1, topos))
  864.     end;
  865.     if s <> nil then if s^.REFS = 0 then disposeS(s);
  866.     getsubS := t
  867. end{ -- getsubS};
  868. SHAR_EOF
  869. fi # end of overwriting check
  870. if test -f 'gtS.p'
  871. then
  872.     echo shar: will not over-write existing file "'gtS.p'"
  873. else
  874. cat << \SHAR_EOF > 'gtS.p'
  875.  
  876.  
  877.  
  878.  
  879. # include "strings.h"
  880.  
  881. function gtS{(left,right: String):Boolean};
  882. {
  883. * left > right
  884. }
  885. begin
  886.     gtS := compare(left, right) = gt
  887. end{ -- gtS};
  888. SHAR_EOF
  889. fi # end of overwriting check
  890. if test -f 'indexS.p'
  891. then
  892.     echo shar: will not over-write existing file "'indexS.p'"
  893. else
  894. cat << \SHAR_EOF > 'indexS.p'
  895.  
  896.  
  897.  
  898.  
  899. # include "strings.h"
  900.  
  901. function indexS{(s: String; i: Nat1):Char};
  902. {
  903. * Returns s[i]
  904. *
  905. * precondition:
  906. *     i <= lengthS(s)
  907. }
  908.    var j: 2..maxint;  chunk: stringtail;
  909. begin
  910.   with s^ do
  911.   if i <= slength then indexS := HEAD[i]
  912.   else begin
  913.     chunk := TAIL;
  914.     for j := 2 to (i-1) div slength do chunk := chunk^.REST;
  915.     indexS := chunk^.MORE[ (i-1) mod slength + 1 ]
  916.   end
  917. end{ -- indexS};
  918. SHAR_EOF
  919. fi # end of overwriting check
  920. if test -f 'initS.p'
  921. then
  922.     echo shar: will not over-write existing file "'initS.p'"
  923. else
  924. cat << \SHAR_EOF > 'initS.p'
  925.  
  926.  
  927.  
  928.  
  929. # include "strings.h"
  930.  
  931. procedure initS{(var s: String)};
  932. {
  933. * Initialises s to be the empty or null string ''
  934. * This is a copy of newS for those people that prefer the name initS!
  935. }
  936. begin
  937.     s := nil
  938. end{ -- initS};
  939. SHAR_EOF
  940. fi # end of overwriting check
  941. if test -f 'initvalparamS.p'
  942. then
  943.     echo shar: will not over-write existing file "'initvalparamS.p'"
  944. else
  945. cat << \SHAR_EOF > 'initvalparamS.p'
  946.  
  947.  
  948.  
  949.  
  950. # include "strings.h"
  951.  
  952. procedure initvalparamS{(var s: String)};
  953. {
  954. * Initialises s, which should be a value parameter, to be
  955. * safely useable within the current procedure.
  956. *
  957. * increase ref count for a by-value param
  958. }
  959. begin
  960.     s^.REFS := s^.REFS + 1
  961. end{ -- initvalparamS};
  962. SHAR_EOF
  963. fi # end of overwriting check
  964. if test -f 'leS.p'
  965. then
  966.     echo shar: will not over-write existing file "'leS.p'"
  967. else
  968. cat << \SHAR_EOF > 'leS.p'
  969.  
  970.  
  971.  
  972.  
  973. # include "strings.h"
  974.  
  975. function leS{(left,right: String):Boolean};
  976. {
  977. * left <= right
  978. }
  979. begin
  980.     leS := compare(left, right) <> gt
  981. end{ -- leS};
  982. SHAR_EOF
  983. fi # end of overwriting check
  984. if test -f 'lengthS.p'
  985. then
  986.     echo shar: will not over-write existing file "'lengthS.p'"
  987. else
  988. cat << \SHAR_EOF > 'lengthS.p'
  989.  
  990.  
  991.  
  992.  
  993. # include "strings.h"
  994.  
  995. function lengthS{(s: String):Nat0};
  996. {
  997. * Returns the dynamic length of a string
  998. }
  999. begin
  1000.     if s = nil then lengthS := 0 else lengthS := s^.LEN
  1001. end{ -- lengthS};
  1002. SHAR_EOF
  1003. fi # end of overwriting check
  1004. if test -f 'ltS.p'
  1005. then
  1006.     echo shar: will not over-write existing file "'ltS.p'"
  1007. else
  1008. cat << \SHAR_EOF > 'ltS.p'
  1009.  
  1010.  
  1011.  
  1012.  
  1013. # include "strings.h"
  1014.  
  1015. function ltS{(left,right: String):Boolean};
  1016. {
  1017. * left < right
  1018. }
  1019. begin
  1020.     ltS := compare(left, right) = lt
  1021. end{ -- ltS};
  1022. SHAR_EOF
  1023. fi # end of overwriting check
  1024. if test -f 'matchS.p'
  1025. then
  1026.     echo shar: will not over-write existing file "'matchS.p'"
  1027. else
  1028. cat << \SHAR_EOF > 'matchS.p'
  1029.  
  1030.  
  1031.  
  1032.  
  1033. # include "strings.h"
  1034.  
  1035. function matchS{(s, pat: String):Nat0};
  1036. {
  1037. * Returns position of pat in s or 0 if not present.
  1038. * Empty strings are not considered present!
  1039. }
  1040.   var diff, lens, lenp, start, next: Nat0;  nomatch: Boolean;
  1041. begin
  1042.   lens := lengthS(s);  lenp := lengthS(pat);
  1043.   if (lens = 0) or (lenp = 0) or (lenp > lens) then
  1044.     matchS := 0
  1045.   else begin
  1046.     start := 0;
  1047.     diff := lens - lenp;
  1048.     repeat
  1049.         start := start+1;
  1050.         next := 0;
  1051.         repeat
  1052.                next := next+1;
  1053.                nomatch := indexS(pat, next) <> indexS(s, start+next-1)
  1054.                 until nomatch or (next = lenp);
  1055.     until not nomatch or (start > diff);
  1056.     if nomatch then matchS := 0 else matchS := start
  1057.   end;
  1058.   { -- possible that function called with constant string for pat }
  1059.   if pat <> nil then if pat^.REFS = 0 then disposeS(pat)
  1060. end{ -- matchS};
  1061. SHAR_EOF
  1062. fi # end of overwriting check
  1063. if test -f 'mk.p'
  1064. then
  1065.     echo shar: will not over-write existing file "'mk.p'"
  1066. else
  1067. cat << \SHAR_EOF > 'mk.p'
  1068.  
  1069.  
  1070.  
  1071.  
  1072. # include "strings.h"
  1073.  
  1074.  
  1075. function mk{(var static: packed array [lo..hi:Integer] of Char; limit: Integer):String};
  1076. {
  1077. * Converts a static Pascal string into a (dynamic) String.
  1078. * From lo to limit rather than hi.
  1079. * This internal procedure may be made generally available
  1080. * should there be a demand.
  1081. }
  1082.    var null: Char;
  1083.        StaticLength: Nat1;
  1084.        i, ExtraChunks, CurrentLength: Nat0;
  1085.        StringHead: String;
  1086.        temp: stringtail;
  1087.        k: Integer;
  1088.        j: 1..slength;
  1089. begin
  1090.     null := chr(0);
  1091.     StaticLength := limit-lo+1;
  1092.     ExtraChunks := (StaticLength-1) div slength;
  1093.     { -- Copy into String head }
  1094.     new(StringHead);
  1095.     with StringHead^ do begin
  1096.         LEN := StaticLength;
  1097.         REFS := 0;
  1098.         TAIL := nil;
  1099.         k := lo;
  1100.         { -- Copy string, null padding if necessary }
  1101.         for j := 1 to slength do
  1102.            if j > StaticLength
  1103.            then HEAD[j] := null
  1104.            else begin
  1105.             HEAD[j] := static[k];
  1106.             k := k+1
  1107.            end;
  1108.         { -- Allocate and link in any extra string chunks needed}
  1109.         for i := 1 to ExtraChunks do begin
  1110.            new(temp); temp^.REST := TAIL; TAIL := temp
  1111.         end;   
  1112.         { -- Loop through copying string tail if required }
  1113.         temp := TAIL;
  1114.         CurrentLength := 0;
  1115.         while temp <> nil do begin
  1116.            with temp^ do begin
  1117.             CurrentLength := CurrentLength+slength;
  1118.                     { -- Copy string, null padding if necessary }
  1119.             for j := 1 to slength do
  1120.                if j+CurrentLength > StaticLength
  1121.                then MORE[j] := null
  1122.                else begin
  1123.                     MORE[j] := static[k];
  1124.                     k := k+1
  1125.                 end
  1126.            end;
  1127.            temp := temp^.REST
  1128.         end{ -- while}
  1129.     end{ -- with};
  1130.     { -- Return the newly created dynamic string }
  1131.     mk := StringHead
  1132. end{ -- mk};
  1133. SHAR_EOF
  1134. fi # end of overwriting check
  1135. if test -f 'mkS.p'
  1136. then
  1137.     echo shar: will not over-write existing file "'mkS.p'"
  1138. else
  1139. cat << \SHAR_EOF > 'mkS.p'
  1140.  
  1141.  
  1142.  
  1143.  
  1144. # include "strings.h"
  1145.  
  1146. function mkS{(static: packed array[lo..hi:Integer]of Char):String};
  1147. {
  1148. * Converts a static Pascal string into a (dynamic) String.
  1149. }
  1150. begin
  1151.     mkS := mk(static, hi)
  1152. end{ -- mkS};
  1153. SHAR_EOF
  1154. fi # end of overwriting check
  1155. if test -f 'mkStaticS.p'
  1156. then
  1157.     echo shar: will not over-write existing file "'mkStaticS.p'"
  1158. else
  1159. cat << \SHAR_EOF > 'mkStaticS.p'
  1160.  
  1161.  
  1162.  
  1163.  
  1164. # include "strings.h"
  1165.  
  1166. procedure mkStaticS{(s: String; var p: packed array[lo..hi:Integer] of Char)};
  1167. {
  1168. * Converts a dynamic string into a static string.
  1169. * p is null padded if necessary.
  1170. * Info will be lost if lengthS(s) > hi-lo+1.
  1171. }
  1172.    var i: Integer; j: Nat1; lens: Nat0; ch,null: Char; sp: CharOfString;
  1173. begin
  1174.     j := 1; lens := lengthS(s);  null := chr(0);
  1175.     if lens <> 0 then
  1176.       first(sp, s);
  1177.     for i := lo to hi do
  1178.       if j <= lens then begin
  1179.         next(sp, ch);
  1180.         p[i] := ch;
  1181.         j := j+1
  1182.       end
  1183.       else
  1184.         p[i] := null
  1185. end{ -- mkStaticS};
  1186. SHAR_EOF
  1187. fi # end of overwriting check
  1188. if test -f 'neS.p'
  1189. then
  1190.     echo shar: will not over-write existing file "'neS.p'"
  1191. else
  1192. cat << \SHAR_EOF > 'neS.p'
  1193.  
  1194.  
  1195.  
  1196.  
  1197. # include "strings.h"
  1198.  
  1199. function neS{(left,right: String):Boolean};
  1200. {
  1201. * left <> right
  1202. }
  1203. begin
  1204.     neS := compare(left, right) <> eq
  1205. end{ -- neS};
  1206. SHAR_EOF
  1207. fi # end of overwriting check
  1208. if test -f 'newS.p'
  1209. then
  1210.     echo shar: will not over-write existing file "'newS.p'"
  1211. else
  1212. cat << \SHAR_EOF > 'newS.p'
  1213.  
  1214.  
  1215.  
  1216.  
  1217. # include "strings.h"
  1218.  
  1219. procedure newS{(var s: String)};
  1220. {
  1221. * Initialises s to be the empty or null string ''
  1222. }
  1223. begin
  1224.     s := nil
  1225. end{ -- newS};
  1226. SHAR_EOF
  1227. fi # end of overwriting check
  1228. if test -f 'next.p'
  1229. then
  1230.     echo shar: will not over-write existing file "'next.p'"
  1231. else
  1232. cat << \SHAR_EOF > 'next.p'
  1233.  
  1234.  
  1235.  
  1236.  
  1237. # include "strings.h"
  1238.  
  1239. procedure next{(var c: CharOfString; var ch: Char)};
  1240. {
  1241. * c is advanced to point to next char in its string and current char
  1242. * returned in ch
  1243. *
  1244. * precondition
  1245. *     c initialised by call to first and not at end of string
  1246. }
  1247.   var nxtchunk: stringtail;
  1248. begin
  1249.     with c do
  1250.      case KIND of
  1251.       true: begin { -- header record }
  1252.          ch := HD^.HEAD[POS];
  1253.          if POS <> slength then
  1254.             POS := POS+1
  1255.          else begin
  1256.             POS := 1;
  1257.             nxtchunk := HD^.TAIL;
  1258.             { -- change variant }
  1259.             KIND := false;
  1260.             TL := nxtchunk
  1261.          end
  1262.         end;
  1263.       false: begin { -- tail record }
  1264.           ch := TL^.MORE[POS];
  1265.           if POS <> slength then
  1266.             POS := POS+1
  1267.           else begin
  1268.             POS := 1;
  1269.             TL := TL^.REST
  1270.           end
  1271.          end
  1272.      end{ -- case}
  1273. end;
  1274. SHAR_EOF
  1275. fi # end of overwriting check
  1276. if test -f 'readS.p'
  1277. then
  1278.     echo shar: will not over-write existing file "'readS.p'"
  1279. else
  1280. cat << \SHAR_EOF > 'readS.p'
  1281.  
  1282.  
  1283.  
  1284.  
  1285. # include "strings.h"
  1286.  
  1287. procedure readS{(var f: Text; var s: String)};
  1288. {
  1289. * Reads a string from text file f; eoln terminating.  The input is
  1290. * left pointing to the beginning of the next line, if any.
  1291. *
  1292. * precondition:
  1293. *    f open for reading & not eof(f)
  1294. }
  1295.     const BufferLength = 120;     
  1296.     var t : String;
  1297.         i : Nat0; 
  1298.      line : packed array [1..BufferLength] of Char;
  1299.         
  1300. begin
  1301.     i := 0;
  1302.     while not eoln(f) and (i <> BufferLength) do begin
  1303.         i := i+1;
  1304.         read(f, line[i])
  1305.     end;
  1306.     if i = 0 then assignS(s, nil) else assignS(s, mk(line, i));
  1307.     { --  Check for more characters on the input line }
  1308.     if (i = BufferLength) and not eoln(f) then begin
  1309.         { --  Get the rest }
  1310.         t := nil;
  1311.         readS(f, t);
  1312.         assignS(s, concatS(s, t))
  1313.     end;
  1314.     if eoln(f) then get(f)
  1315. end{ -- readS};
  1316. SHAR_EOF
  1317. fi # end of overwriting check
  1318. if test -f 'readtS.p'
  1319. then
  1320.     echo shar: will not over-write existing file "'readtS.p'"
  1321. else
  1322. cat << \SHAR_EOF > 'readtS.p'
  1323.  
  1324.  
  1325.  
  1326.  
  1327. # include "strings.h"
  1328.  
  1329. procedure readtS{(var f: Text; var s: String; function stop(c:Char):Boolean)};
  1330. {
  1331. * Reads a string from text file f; eoln or stop(c) returning true
  1332. * (whichever occurs first) terminating.  In either case,
  1333. * input is left positioned at the terminator.
  1334. *
  1335. * precondition:
  1336. *    f open for reading & not eof(f)
  1337. }
  1338.     const BufferLength = 120;
  1339.     var t : String;
  1340.         i : Nat0; 
  1341.      line : packed array [1..BufferLength] of Char;
  1342. begin
  1343.     i := 0;
  1344.     while not eoln(f) and (i <> BufferLength) and not stop(f^) do begin
  1345.         i := i+1;
  1346.         read(f, line[i])
  1347.     end;
  1348.     if i = 0 then assignS(s, nil) else assignS(s, mk(line, i));
  1349.     { --  Check for more characters on the input line }
  1350.     if (i = BufferLength) and not stop(f^) and not eoln(f) then begin
  1351.         { --  Get the rest }
  1352.         t := nil;
  1353.         readS(f, t);
  1354.         assignS(s, concatS(s, t))
  1355.     end
  1356. end{ -- readtS};
  1357. SHAR_EOF
  1358. fi # end of overwriting check
  1359. if test -f 'repS.p'
  1360. then
  1361.     echo shar: will not over-write existing file "'repS.p'"
  1362. else
  1363. cat << \SHAR_EOF > 'repS.p'
  1364.  
  1365.  
  1366.  
  1367.  
  1368. # include "strings.h"
  1369.  
  1370. function repS{(s: String; n: Nat0):String};
  1371. {
  1372. * [[ Returns s * n ]]
  1373. * Replicates s, n times.
  1374. }
  1375.   var  null, ChFromS: Char;
  1376.        lens, StaticLength: Nat0;
  1377.        i, ExtraChunks, CurrentLength: Nat0;
  1378.        StringHead: String;
  1379.        temp: stringtail;
  1380.        k: Integer;
  1381.        j: 1..slength;
  1382.        sp: CharOfString;
  1383. begin
  1384.   null := chr(0); lens := lengthS(s); StaticLength := lens*n;
  1385.   if StaticLength = 0 then repS := nil { -- emptyS} else begin
  1386.     ExtraChunks := (StaticLength-1) div slength;
  1387.     { -- Copy into String head }
  1388.     new(StringHead);
  1389.     with StringHead^ do begin
  1390.         LEN := StaticLength;
  1391.         REFS := 0;
  1392.         TAIL := nil;
  1393.         first(sp, s); k := 1;
  1394.         { -- Copy string, null padding if necessary }
  1395.         for j := 1 to slength do
  1396.            if j > StaticLength
  1397.            then HEAD[j] := null
  1398.            else begin
  1399.             next(sp, ChFromS);
  1400.             if k = lens then begin
  1401.             k := 1; first(sp, s)
  1402.             end else
  1403.             k := k+1;
  1404.             HEAD[j] := ChFromS
  1405.            end;
  1406.         { -- Allocate and link in any extra string chunks needed}
  1407.         for i := 1 to ExtraChunks do begin
  1408.            new(temp); temp^.REST := TAIL; TAIL := temp
  1409.         end;   
  1410.         { -- Loop through copying string tail if required }
  1411.         temp := TAIL;
  1412.         CurrentLength := 0;
  1413.         while temp <> nil do begin
  1414.            with temp^ do begin
  1415.             CurrentLength := CurrentLength+slength;
  1416.                     { -- Copy string, null padding if necessary }
  1417.             for j := 1 to slength do
  1418.                if j+CurrentLength > StaticLength
  1419.                then MORE[j] := null
  1420.                else begin
  1421.                     next(sp, ChFromS);
  1422.                     if k = lens then begin
  1423.                         k := 1; first(sp, s)
  1424.                     end else
  1425.                         k := k+1;
  1426.                     MORE[j] := ChFromS
  1427.                 end
  1428.            end;
  1429.            temp := temp^.REST
  1430.         end{ -- while};
  1431.         end{ -- with};
  1432.     { -- Return the newly created dynamic string }
  1433.     repS := StringHead
  1434.   end;
  1435.   if s <> nil then if s^.REFS = 0 then disposeS(s);
  1436. end{ -- repS};
  1437. SHAR_EOF
  1438. fi # end of overwriting check
  1439. if test -f 'updateS.p'
  1440. then
  1441.     echo shar: will not over-write existing file "'updateS.p'"
  1442. else
  1443. cat << \SHAR_EOF > 'updateS.p'
  1444.  
  1445.  
  1446.  
  1447.  
  1448. # include "strings.h"
  1449.  
  1450. procedure updateS{(var s: String; i: Nat1; c:Char)};
  1451. {
  1452. * Updates the string s at position  i  with the char c.
  1453. * if i > lengthS(s), s is first space filled upto i-1.
  1454. }
  1455.    var j: 2..maxint;
  1456.        chunk: stringtail;
  1457.   
  1458.   procedure copy(var lhs: String; rhs: String);
  1459.   {
  1460.   *  lhs := rhs (forces a string copy)
  1461.   }
  1462.     var ExtraChunks: Nat0; i: Nat1; temp, l, r: stringtail;
  1463.   begin
  1464.     new(lhs);
  1465.     { -- Copy string head }
  1466.     lhs^ := rhs^;
  1467.     with lhs^ do begin
  1468.       REFS := 1;
  1469.       ExtraChunks := (rhs^.LEN-1) div slength;
  1470.       TAIL := nil;
  1471.           { -- Allocate and link in any extra string chunks needed }
  1472.       for i := 1 to ExtraChunks do begin
  1473.         new(temp); temp^.REST := TAIL; TAIL := temp
  1474.        end
  1475.      end;
  1476.         { -- Loop through copying string tail if required }
  1477.      l := lhs^.TAIL;  r := rhs^.TAIL;
  1478.      for i := 1 to ExtraChunks do begin
  1479.         l^.MORE := r^.MORE;
  1480.         l := l^.REST;
  1481.         r := r^.REST
  1482.      end
  1483.   end{ -- copy};
  1484.  
  1485.  
  1486. begin { --  of updateS }
  1487.   if s <> nil then
  1488.      with s^ do
  1489.       if REFS > 1 then begin
  1490.     { -- Make a unique copy before update }
  1491.     REFS := REFS-1;    
  1492.     copy(s, s) { --  N.B. careful (!) use of var and value params. }
  1493.       end;
  1494.   if i <= lengthS(s) then
  1495.     with s^ do
  1496.       if i <= slength
  1497.       then { -- pos is in string head } HEAD[i] := c
  1498.       else begin
  1499.         { -- find tail chunk containing pos. i }
  1500.         chunk := TAIL;
  1501.         for j := 2 to (i-1) div slength do
  1502.             chunk := chunk^.REST;
  1503.         chunk^.MORE[ (i-1) mod slength + 1 ]  := c
  1504.       end
  1505.   else { -- Inefficient but rare case }
  1506.     assignS(s, concatS(s,concatS(repS(CtoS(' '),i-lengthS(s)-1),CtoS(c))))
  1507. end{ -- updateS};
  1508. SHAR_EOF
  1509. fi # end of overwriting check
  1510. if test -f 'writeS.p'
  1511. then
  1512.     echo shar: will not over-write existing file "'writeS.p'"
  1513. else
  1514. cat << \SHAR_EOF > 'writeS.p'
  1515.  
  1516.  
  1517.  
  1518. # include "strings.h"
  1519.  
  1520. procedure writeS{var f: Text; s: String)};
  1521. {
  1522. * Write the dynamic string s to file f
  1523. *
  1524. * precondition:
  1525. *    f open for writing    
  1526. }
  1527.    var temp: stringtail;
  1528.        i, Currentlength: Nat1; ExtraChunks: Nat0;
  1529. begin
  1530.     if s = nil then { -- Do nothing if string = '' }
  1531.     else begin
  1532.      with s^ do begin
  1533.         ExtraChunks := (LEN-1) div slength;
  1534.         if LEN > slength then
  1535.             CurrentLength := slength
  1536.         else
  1537.             CurrentLength := LEN;
  1538.         write(f, HEAD:CurrentLength);
  1539.         temp := TAIL;
  1540.         { -- Output any tail chunks }
  1541.         for i := 1 to ExtraChunks do with temp^ do
  1542.             if i <> ExtraChunks then begin
  1543.                 write(f, MORE);
  1544.                 temp := REST
  1545.             end else 
  1546.                 if LEN mod slength <> 0 then
  1547.                 write(f, MORE:(LEN mod slength))
  1548.                 else
  1549.                 write(f, MORE)
  1550.      end;
  1551.      { -- may have been asked to output a constant string }
  1552.      if s^.REFS = 0 then disposeS(s)
  1553.     end
  1554. end{ -- writeS};
  1555.  
  1556.  
  1557. SHAR_EOF
  1558. fi # end of overwriting check
  1559. if test -f 'writelnS.p'
  1560. then
  1561.     echo shar: will not over-write existing file "'writelnS.p'"
  1562. else
  1563. cat << \SHAR_EOF > 'writelnS.p'
  1564.  
  1565.  
  1566.  
  1567.  
  1568. # include "strings.h"
  1569.  
  1570. procedure writelnS{(var f: Text; s: String)};
  1571. {
  1572. * Write the dynamic string s to file f followed by an eoln marker
  1573. *
  1574. * precondition:
  1575. *    f open for writing    
  1576. }
  1577. begin
  1578.     writeS(f, s);
  1579.     writeln(f)
  1580. end{ -- writelnS};
  1581. SHAR_EOF
  1582. fi # end of overwriting check
  1583. if test -f 'Makefile'
  1584. then
  1585.     echo shar: will not over-write existing file "'Makefile'"
  1586. else
  1587. cat << \SHAR_EOF > 'Makefile'
  1588. PFLAGS=-O -L
  1589.  
  1590. OBJ= initvalparamS.o finalS.o initS.o mk.o mkS.o CtoS.o writeS.o emptyS.o lengthS.o writelnS.o assignS.o repS.o concatS.o disposeS.o readtS.o readS.o indexS.o getsubS.o mkStaticS.o matchS.o updateS.o compare.o eqS.o\
  1591. neS.o ltS.o \
  1592. first.o next.o gtS.o leS.o geS.o newS.o
  1593.  
  1594. strings.a: strings.h  ${OBJ}
  1595.     ar ruv strings.a ${OBJ}
  1596.     ranlib strings.a
  1597.  
  1598. ${OBJ}: strings.h 
  1599. SHAR_EOF
  1600. fi # end of overwriting check
  1601. #    End of shell archive
  1602. exit 0
  1603.  
  1604.  
  1605. ----- End Forwarded Message -----
  1606.